import React from 'react'

class FormStore {
  constructor(props) {
    this.store = {}
    //存储Field实例
    this.fieldEntities = []
    this.callback = {}
    this.errorObj = []
  }
  //订阅
  registerField = (entity) => {
    this.fieldEntities.push(entity)
    return () => {
      this.fieldEntities = this.fieldEntities.filter((item) => item !== entity)
      delete this.store[entity.props.name]
    }
  }

  setCallback = (callback) => {
    this.callback = {
      ...this.callback,
      ...callback
    }
  }
  getFieldValue = (name) => {
    return this.store[name]
  }
  setFieldsValue = (newStore) => {
    this.store = {
      ...this.store,
      ...newStore
    }
    //更新组件
    this.fieldEntities.forEach((entity) => {
      const { name } = entity.props
      Object.keys(newStore).forEach((key) => {
        if (name === key) {
          entity.onStoreChange()
        }
      })
    })
  }
  //校验
  validate = () => {
    //错误信息
    let err = []
    this.fieldEntities.forEach((entity) => {
      const { name, rules } = entity.props

      let value = this.getFieldValue(name)
      let rule = rules && rules[0]
      if (rule && rule.required && (value === undefined || value === '')) {
        err.push({
          [name]: rule.message,
          value
        })
      }
    })
    return err
  }
  submit = () => {
    let err = this.validate()
    const { onFinish, onFinishFailed } = this.callback
    if (err.length === 0) {
      onFinish(this.store)
      this.errorObj = []
    } else if (err.length > 0) {
      this.errorObj = err
      onFinishFailed(err)
    }
  }
  getForm = () => {
    return {
      submit: this.submit,
      getFieldValue: this.getFieldValue,
      setFieldsValue: this.setFieldsValue,
      registerField: this.registerField,
      setCallback: this.setCallback,
      err: this.errorObj
    }
  }
}

//自定义hook
export default function useForm() {
  const formRef = React.useRef()
  if (!formRef.current) {
    const formStore = new FormStore()
    formRef.current = formStore.getForm()
  }
  return formRef.current
}
